using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace Pyramid
{
    abstract class Blend
    {
        public GImage FineImage;
        public GImage CoarseImage;
        public Boolean AmplifyDetails;
        public Boolean TransferDetails;
        public double Amp_Factor;
        protected int fine_level;
        protected int coarse_level;
        protected List<GImage> ImagePyramid;
        protected List<ImageWithDetail> Fine_Image_Pyramid;
        protected Multiresolution MR;
        protected void init_general(int MRMethod, int ExtensionMethod)
        {
            switch (MRMethod)
            {
                case 0:
                    MR = new CatmullRom();
                    break;
                case 1:
                    MR = new Chaikin();
                    break;
                case 2:
                    MR = new ChaikinWithDetail();
                    break;
                case 3:
                    MR = new Haar();
                    break;
                case 4:
                    MR = new Faber();
                    break;

            }
            MR.ExtensionMethod = ExtensionMethod;
            MR.AmplifyDetails = AmplifyDetails;
            MR.Amp_Factor = Amp_Factor;
            coarse_level = 1;
            fine_level = coarse_level + (int)Math.Log(FineImage.Width / CoarseImage.Width, 2);

            //build the gaussian pyramid of the fine image
            Fine_Image_Pyramid = new List<ImageWithDetail>();

            ImageWithDetail temp = new ImageWithDetail();

            temp.TheImage = new GImage(FineImage);
            temp.TheDetails = new List<GImage>();

            Fine_Image_Pyramid.Add(temp);
            for (int l = fine_level - 1; l >= coarse_level; l--)
            {
                temp = new ImageWithDetail(MR.DownSample(temp));
                Fine_Image_Pyramid.Add(temp);
            }
            Fine_Image_Pyramid.Reverse();

            if(TransferDetails)
                if (Fine_Image_Pyramid[0].TheDetails.Count > 0)
                {
                    //add the details of the fine image to the coarse image 
                    CoarseImage = CoarseImage + Fine_Image_Pyramid[0].TheDetails[Fine_Image_Pyramid[0].TheDetails.Count-3];
                }
         
        }
        public double Analyze()
        {
            double s = 0;
            int nsize = 11;
            ImageWithDetail xl=new ImageWithDetail(ImagePyramid[0]);
            
            ImageWithDetail xll=new ImageWithDetail();
            
            for (int l = 1; l < fine_level; l++)
            {
                xll.TheImage = ImagePyramid[l];
                GImage temp=new GImage(MR.DownSample(xll).TheImage);
                s += xl.TheImage.StructuralSimilarity(temp, nsize);
                xl.TheImage = new GImage(xll.TheImage);
                
                
            }
            return s;
        }
        public bool Applicable(int level)
        {
            return (level <= fine_level && level >= coarse_level);
        }
        
        public GImage IntermediateImage(int level)
        {
            if (Applicable(level))           
                return ImagePyramid[--level];
            else
                return null;
        }
        public Point Register_Fine_and_Coarse()
        {
            //go to very low resolution and then fo the registeration 
            Point r = new Point();
            //first make the fine image as small as the coarse image
            
            ImageWithDetail tempfine = new ImageWithDetail(FineImage);

            while (tempfine.TheImage.Width != CoarseImage.Width && tempfine.TheImage.Height != CoarseImage.Height)
            {
                tempfine = MR.DownSample(tempfine);
            }
            
            //if that's small enough then do the registeration
            r = CoarseImage.Register(tempfine.TheImage, 10);
            return r;
        }
        public abstract void Init(int MRMethod, int ExtensionMethod);

    }
}
